package com.gitee.wsl.text.reader

import com.gitee.wsl.text.Sentence
import kotlin.jvm.JvmOverloads

/**
 * 本类用于拆分字符串，默认的分隔符为逗号
 * 分割时将跳过单双引号与指定种类括号内的分隔符
 * 特别注意：空白串中有一个标记，其值也为空白串
 * @author RunQian
 */
class ArgumentTokenizer @JvmOverloads constructor(
    s: String,
    delim: Char = ',',
    ignoreParentheses: Boolean = false,
    ignoreBrackets: Boolean = false,
    ignoreBraces: Boolean = false,
    ignoreSingleQuotation: Boolean = false,
) {
    private var str: String? = null // 源串
    private var len = 0 // 长度
    private var index = 0 // 当前分割的位置
    private var delim = ',' // 分隔符，默认为逗号

    private var parentheses = false // 是否忽略圆括号内的分隔符
    private var brackets = false // 是否忽略中括号内的分隔符
    private var braces = false // 是否忽略花括号内的分隔符
    private var singleQuotation = false // 是否忽略单引号内的分隔符

    private var count = false // 只取数量，不取分割后的子串

    /**
     * 为指定字符串构造一个参数分割器
     * @param s 指定的字符串
     * @param ignoreParentheses 忽略圆括号内的分隔符
     * @param ignoreBrackets 忽略中括号内的分隔符
     * @param ignoreBraces 忽略花括号内的分隔符
     */
    constructor(
        s: String,
        ignoreParentheses: Boolean,
        ignoreBrackets: Boolean,
        ignoreBraces: Boolean,
    ) : this(s, ',', ignoreParentheses, ignoreBrackets, ignoreBraces)

    init {
        // str = s.trim();
        str = s
        this.delim = delim
        this.parentheses = !ignoreParentheses
        this.brackets = !ignoreBrackets
        this.braces = !ignoreBraces
        this.singleQuotation = !ignoreSingleQuotation
        len = if ((str == null || str!!.isEmpty())) -1 else str!!.length
    }

    /**
     * 取下一个标记
     * @return 若字符串为null，则返回null。若hasNext()或hasMoreTokens()为真，则返回
     * 分割符分割的标记(非空串或空串)，否则返回null。 若不匹配的引号(单/双)则返回引号后的所有字符
     * 若引号前转义符\，则此引号不起引号作用
     */
    fun next(): String? {
        if (str == null || index > len) return null
        val old = index
        while (index <= len) {
            if (index == len) {
                index++
                if (len > 1 && str!![len - 1] == delim) return if (count) null else ""
                break
            }
            val ch = str!![index]
            if (ch == '\\') {
                index += 2
                continue
            }
            if (ch == '\"' || (singleQuotation && ch == '\'')) {
                val tmp: Int = Sentence.scanQuotation(str!!, index)
                if (tmp < 0) {
                    index = len + 1
                    return if (count) null else str!!.substring(old)
                }
                index = tmp + 1
                continue
            }
            if (parentheses && ch == '(') {
                val tmp: Int = Sentence.scanParenthesis(str!!, index)
                if (tmp < 0) {
                    index = len + 1
                    return if (count) null else str!!.substring(old)
                }
                index = tmp + 1
                continue
            }
            if (brackets && ch == '[') {
                val tmp: Int = Sentence.scanBracket(str!!, index)
                if (tmp < 0) {
                    index = len + 1
                    return if (count) null else str!!.substring(old)
                }
                index = tmp + 1
                continue
            }
            if (braces && ch == '{') {
                val tmp: Int = Sentence.scanBrace(str!!, index)
                if (tmp < 0) {
                    index = len + 1
                    return if (count) null else str!!.substring(old)
                }
                index = tmp + 1
                continue
            }
            index++
            if (ch == delim) break
        }
        return if (count) null else str!!.substring(old, index - 1)
    }

    /**
     * 取下一个标记
     * @return 若字符串为null，则返回null。若hasMoreTokens()为真，则返回分割符分割
     * 的标记(非空串或空串)，否则返回null。
     */
    fun nextToken(): String? {
        return next()
    }

    /**
     * 取下一个标记
     * @return 若字符串为null，则返回null。若hasMoreTokens()为真，则返回分割符分割
     * 的标记(非空串或空串)，否则返回null。
     */
    fun nextElement(): String {
        return next()!!
    }

    /**
     * 计算指定字符串中所有未访问标记的个数。
     * @return 字符串中标记数
     */
    fun countTokens(): Int {
        val j = index
        count = true
        var i = 0
        while (index <= len) {
            next()
            i++
        }

        index = j
        count = false
        return i
    }

    /**
     * 检查是否还有标记
     * @return 还有标记返回true，否则返回false
     */
    fun hasNext(): Boolean {
        return index <= len
    }

    /**
     * 检查是否还有标记
     * @return 还有标记返回true，否则返回false
     */
    fun hasMoreTokens(): Boolean {
        return hasNext()
    }

    /**
     * 检查是否还有标记
     * @return 还有标记返回true，否则返回false
     */
    fun hasMoreElements(): Boolean {
        return hasNext()
    }
}
